package org.brownflat.lighthouse.monitoring.ci.teamcity;

import org.brownflat.lighthouse.monitoring.ci.Build;
import org.brownflat.lighthouse.monitoring.ci.Builder;
import org.brownflat.lighthouse.monitoring.ci.Feed;
import org.brownflat.lighthouse.monitoring.xml.XMLDocument;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class TeamCityBuilder implements Builder<Feed, String> {

    private List<String> buildNames;

    private static HashMap<String, String> namespaceContexts;

    static {
        namespaceContexts = new HashMap<String, String>();
        namespaceContexts.put("atom", "http://www.w3.org/2005/Atom");
        namespaceContexts.put("dc", "http://purl.org/dc/elements/1.1/");
    }

    public TeamCityBuilder(String... buildNames) {
        this.buildNames = Arrays.asList(buildNames);
    }

    public TeamCityBuilder() {
        this.buildNames = new ArrayList<String>();
    }

    public Feed build(String input) {
        XMLDocument document = new XMLDocument(input);
        document.setNamespaceContexts(namespaceContexts);

        List<XMLDocument> entryDocuments = document.documentsAt("/atom:feed/child::atom:entry");
        Feed feed = new Feed();

        for (XMLDocument xmlDocument : entryDocuments) {
            Build build = buildBuild(xmlDocument);
            if (matchesSelectedBuilds(build)) {
                feed.addBuild(build);
            }
        }
        return feed;
    }

    private boolean matchesSelectedBuilds(Build build) {
        if (buildNames.isEmpty()) {
            return true;
        }
        for (String thisName : buildNames) {
            if (build.getKey().matches(thisName)) {
                return true;
            }
        }
        return false;
    }

    private Build buildBuild(XMLDocument xmlDocument) {
        Build entry = new Build();
        entry.setName(getName(xmlDocument.selectValueAt("/atom:entry/atom:title")));
        entry.setProject(getProject(xmlDocument.selectValueAt("/atom:entry/atom:title")));
        entry.setBroken(xmlDocument.selectValueAt("/atom:entry/atom:author/atom:name").contains("Failed Build"));
        entry.setDate(getDate(xmlDocument.selectValueAt("/atom:entry/dc:date")));
        return entry;
    }

    private String getName(String title) {
        Pattern outerPattern = Pattern.compile("^Build (.*)::(.*\\dd*).*$");
        Matcher outerMatcher = outerPattern.matcher(title);
        if (outerMatcher.matches()) {
            return outerMatcher.group(2);
        }
        throw new RuntimeException("Couldn't match key pattern in RSS feed for value " + title);
    }

    private String getProject(String title) {
        Pattern outerPattern = Pattern.compile("^Build (.*)::.*$");
        Matcher outerMatcher = outerPattern.matcher(title);
        if (outerMatcher.matches()) {
            return outerMatcher.group(1);
        }
        throw new RuntimeException("Couldn't match project name pattern in RSS feed");
    }

    private DateTime getDate(String dateValue) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
        try {
            Date date = fmt.parse(dateValue);
            return new DateTime(date, DateTimeZone.UTC);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}
